﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Microsoft.Office.Interop.Word;

namespace SetLanguageInfo
{
    public class LanguageHelper
    {
        private const string FILE_INFOS = "FileInfos";
        public const string LANG_CONVERT_KEY_WORD = "_Lang";
        private const string PgListKeyWord = "PaginationGrid:PaginationGrid", SCRIPT_KEY = "script";
        public const string LANG_KEY = "KEY", LANG_CN = "CN", LANG_HK = "HK";

        public LanguageHelper()
        {
            FileEncoding = Encoding.Default;
        }

        public Encoding FileEncoding { set; get; }

        public XmlNode SetNode(XmlNode parentNode, string nodeName, XmlDocument xmlDoc)
        {
            XmlNode node = null;
            if (!string.IsNullOrEmpty(nodeName) && parentNode != null)
            {
                node = parentNode.SelectSingleNode(nodeName);
                if (node == null)
                {
                    node = xmlDoc.CreateElement(nodeName);
                    parentNode.AppendChild(node);
                }
            }
            return node;
        }


        private string GetNodeAttrVal(XmlNode n, string strAttrName)
        {
            if (n.Attributes[strAttrName] != null)
            {
                string strVal = n.Attributes[strAttrName].Value;
                if (!string.IsNullOrEmpty(strVal))
                    return strVal;
            }
            return "";
        }

        private void CopyNodeAttr(XmlNode srcNode, XmlNode tarNode, string strAttrName, XmlDocument doc)
        {
            string strAttrVal = GetNodeAttrVal(srcNode, strAttrName);
            if (strAttrVal.Length > 0)
            {
                XmlAttribute attr = tarNode.Attributes[strAttrName] ?? doc.CreateAttribute(strAttrName);
                attr.Value = strAttrVal;
                tarNode.Attributes.Append(attr);
            }
        }

        public const string LanguageKeyWord = "LanguageKeyWord_";

        private void SetInfoByExecFile(string csFilePath, XmlDocument doc, NameObjectDictionary ndInfo)
        {
            var scAfterEdit = new StringCollection();
            if (File.Exists(csFilePath))
            {
                var sr = new StreamReader(csFilePath, FileEncoding);
                try
                {
                    while (sr.Peek() > 0)
                    {
                        string rowText = sr.ReadLine();
                        string rowInfo = rowText.Trim();
                        string strOutputString = rowText;

                        if (rowInfo.Length > 0)
                        {
                            if (!rowInfo.StartsWith("<%"))
                            {
                                StringCollection scInfo = GetWordsIsCnOrTw(rowInfo);
                                for (var i = 0; i < scInfo.Count;i++ )
                                {
                                    var strInfo = scInfo[i];
                                    XmlNode childNode = null;
                                    if (ndInfo.Contains(strInfo))
                                        childNode = ((XmlNode)ndInfo[strInfo]);
                                    if (childNode == null)
                                    {
                                        int num = ndInfo.Count + 1;
                                        childNode =
                                            doc.CreateElement(LanguageKeyWord +
                                                              num.ToString().PadLeft(5, '0'));
                                        XmlAttribute attr = doc.CreateAttribute("Value");
                                        XmlAttribute attrSrc = doc.CreateAttribute("Src");
                                        attr.Value = strInfo;
                                        if (strInfo.IndexOf("票據編號") > -1 || strInfo.IndexOf("票据编号") > -1)
                                        {
                                            var ss = "";
                                        }
                                        childNode.Attributes.Append(attr);
                                        childNode.Attributes.Append(attrSrc);
                                    }
                                    var di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

                                    if (di != null && di.Parent != null)
                                        di = di.Parent;
                                    if (di == null) return;
                                    string strVal = childNode.Attributes["Value"].Value;

                                    string strSrc = childNode.Attributes["Src"].Value;
                                    string csFileName = csFilePath.Substring(csFilePath.LastIndexOf('\\') + 1);
                                    if (strSrc.IndexOf(csFileName) == -1)
                                        childNode.Attributes["Src"].Value = strSrc + csFileName + ",";

                                    ndInfo[strInfo] = childNode;
                                    int startIndex = strOutputString.IndexOf(strVal);
                                    int reStartIndex = strOutputString.IndexOf(strVal) + strVal.Length;
                                    if (startIndex > -1 && reStartIndex <= strOutputString.Length)
                                    {
                                        string strTempHead = strOutputString.Substring(0, startIndex);
                                        string strTempLast = "";
                                        if (strOutputString.Length >= (reStartIndex + 1))
                                            strTempLast = strOutputString.Substring(reStartIndex);
                                        strOutputString = strTempHead + childNode.Name + strTempLast;
                                    }
                                }
                            }
                        }
                        scAfterEdit.Add(strOutputString);
                    }
                }
                finally
                {
                    sr.Close();
                }

                if (File.Exists(csFilePath)) File.Delete(csFilePath);
                var fs = new FileStream(csFilePath, FileMode.OpenOrCreate);
                var sw = new StreamWriter(fs, FileEncoding);
                try
                {
                    foreach (string str in scAfterEdit)
                        sw.WriteLine(str);
                }
                finally
                {
                    sw.Close();
                    fs.Close();
                }
            }
        }



        //public StringCollection GetWordsIsCnOrTw(string words)
        //{
        //    var scVal = new StringCollection();
        //    string TmmP;
        //    bool isCn = false;
        //    var sb = new StringBuilder();
        //    for (int i = 0; i < words.Length; i++)
        //    {
        //        TmmP = words.Substring(i, 1);
        //        byte[] sarr = Encoding.GetEncoding("gb2312").GetBytes(TmmP);
        //        isCn = (sarr.Length == 2);
        //        if (isCn)
        //            sb.Append(TmmP);
        //        if (sb.Length > 0 && (isCn == false || (i + 1) == words.Length))
        //        {
        //            scVal.Add(sb.ToString());
        //            sb = new StringBuilder();
        //        }
        //    }
        //    return scVal;
        //}


        /*
           GBK范围：   
  1st   byte         2nd   byte   
  0x81~0xfe       0x40~0x7e   and   0x80~0xfe   
    
  BIG5范围：   
  1st   byte         2nd   byte   
  0x81~0xfe       0x40~0x7e   and   0xa1~0xfe
         */

        public StringCollection GetWordsIsCnOrTw(string words)
        {
            var scVal = new StringCollection();
            var sb = new StringBuilder();
            var reg = new Regex("^[\u4e00-\u9fa5]$");
            for (int i = 0; i < words.Length; i++)
            {
                var tempChar = words.Substring(i,1);
                var isCn = (reg.IsMatch(tempChar));
                if (isCn)
                    sb.Append(tempChar);
                if (sb.Length > 0 && (isCn == false || (i + 1) == words.Length))
                {
                    scVal.Add(sb.ToString());
                    sb = new StringBuilder();
                }
            }
            return scVal;
        }


        public void SetLanguageInfoFile(XmlDocument xmlDoc, string csFilePath, string languageFilePath,
                                        NameObjectDictionary ndInfo)
        {
            if (ndInfo == null)
                ndInfo = new NameObjectDictionary();
            //if (csFilePath.ToLower().EndsWith("designer.cs"))
            //    return;
            SetInfoByExecFile(csFilePath, xmlDoc, ndInfo);
        }

        public void SetLanguageInfoFile(XmlDocument xmlDoc, StringCollection xmlFilePaths, string languageFilePath,
                                        NameObjectDictionary ndInfo)
        {
            if (!File.Exists(languageFilePath))
            {
                XmlElement root = xmlDoc.CreateElement("Setting");
                xmlDoc.AppendChild(root);
                xmlDoc.Save(languageFilePath);
            }
            xmlDoc.Load(languageFilePath);
            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            foreach (string str in xmlFilePaths)
                SetLanguageInfoFile(xmlDoc, str, languageFilePath, ndInfo);
        }

        public void CreateConvertLangXML(string strKeyLangSettingPath,string langKeyFlag)
        {
            string strHKLangFilePath = strKeyLangSettingPath.Replace(LANG_KEY+".xml", langKeyFlag+".xml");
            if (File.Exists(strHKLangFilePath)) File.Delete(strHKLangFilePath);
            var cnSr = new StreamReader(strKeyLangSettingPath, FileEncoding);
            string strLangInfo = "";
            var sdTemp = new StringBuilder();
            try
            {
                strLangInfo = cnSr.ReadToEnd();
            }
            finally
            {
                cnSr.Close();
            }
            var hkFs = new FileStream(strHKLangFilePath, FileMode.OpenOrCreate);
            if (langKeyFlag == LANG_HK)
                strLangInfo = CN_To_TW(strLangInfo);
            else if (langKeyFlag == LANG_CN)
                strLangInfo = TW_To_CN(strLangInfo);
            var hkSw = new StreamWriter(hkFs, FileEncoding);
            try
            {
                hkSw.Write(strLangInfo);
            }
            finally
            {
                hkSw.Close();
                hkFs.Close();
            }
        }

        public void OutputLangSettingXmlFile(XmlDocument xmlDoc, string languageFilePath, NameObjectDictionary ndInfo)
        {
            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            XmlNode csNode = SetNode(settingNode, "FileInfos", xmlDoc);
            foreach (XmlNode n in ndInfo.Values)
                csNode.AppendChild(n);
            var fs = new FileStream(languageFilePath, FileMode.OpenOrCreate);
            var sw = new StreamWriter(fs, FileEncoding);
            try
            {
                xmlDoc.Save(sw);
            }
            finally
            {
                sw.Close();
                fs.Close();
            }
            CreateConvertLangXML(languageFilePath,LANG_CN);
            CreateConvertLangXML(languageFilePath,LANG_HK);
        }

        public void EditFileInfo(StringCollection xmlFilePaths, string strBaseDirPath, NameObjectDictionary ndInfo)
        {
            ndInfo = GetSrcFileInfosFromLanguageSettingXml(strBaseDirPath);
            for (int i = 0; i < xmlFilePaths.Count; i++)
            {
                EditFileInfo(xmlFilePaths[i], ndInfo);
            }
        }

        public void EditFileInfo(string filePath, NameObjectDictionary htSrc)
        {
            string strInfo = "";
            if (!File.Exists(filePath))
                return;
            var sr = new StreamReader(filePath);
            try
            {
                strInfo = sr.ReadToEnd();
            }
            finally
            {
                sr.Close();
            }
            SetLangKeyInfoForString(ref strInfo, htSrc);
            if (File.Exists(filePath)) File.Delete(filePath);
            var fs = new FileStream(filePath, FileMode.OpenOrCreate);
            var sw = new StreamWriter(fs, Encoding.Default);
            try
            {
                sw.Write(strInfo);
            }
            finally
            {
                sw.Close();
                fs.Close();
            }
        }

        public void GetDirAllFileNamesForSetting(string dirPath, string[] strSeachKeys, StringCollection scFileNames)
        {
            foreach (string strSeachKey in strSeachKeys)
            {
                string[] files = Directory.GetFiles(dirPath, strSeachKey, SearchOption.AllDirectories);
                foreach (string str in files)
                {
                    string tempStr = str.ToLower();
                    if (tempStr.IndexOf("_svn") > -1 || tempStr.EndsWith("cn.xml") || tempStr.EndsWith("key.xml") || tempStr.EndsWith("hk.xml") 
                       // ||tempStr.EndsWith("designer.cs")
                        || tempStr.IndexOf("\\bin\\") > -1 || tempStr.IndexOf("\\obj\\") > -1 ||
                        tempStr.IndexOf("\\LanguageSetting\\") > -1)
                        continue;
                    scFileNames.Add(str);
                }
            }
        }

        public void GetDirAllFileNamesForPro(string dirPath, StringCollection scFileNames)
        {
            string[] files = Directory.GetFiles(dirPath, "*", SearchOption.AllDirectories);
            foreach (string str in files)
            {
                string tempStr = str.ToLower();
                if (tempStr.IndexOf("_svn") > -1 || tempStr.IndexOf("\\bin\\") > -1 || tempStr.IndexOf("\\obj\\") > -1
                    || tempStr.EndsWith("resharper.user") || tempStr.IndexOf("_resharper") > -1)
                    continue;
                scFileNames.Add(str);
            }
        }

        public NameObjectDictionary GetSrcFileInfosFromLanguageSettingXml(string strBaseDirPath)
        {
            var ht = new NameObjectDictionary();
            var doc = new XmlDocument();
            doc.Load(strBaseDirPath + "Language\\CN.xml");
            XmlNodeList nl = doc.SelectNodes("/Setting/FileInfos/*");
            if (nl == null)
                return ht;
            foreach (XmlNode n in nl)
            {
                string strVal = GetNodeAttrVal(n, "Value");
                string strNodeName = n.Name;
                ht.Add(strVal, strNodeName);
            }
            return ht;
        }

        public Hashtable GetTargetFileInfosFromLanguageSettingXml(string lanuageKey, string strBaseDirPath)
        {
            var ht = new Hashtable();
            var doc = new XmlDocument();
            doc.Load(strBaseDirPath + "Language\\" + lanuageKey + ".xml");
            XmlNodeList nl = doc.SelectNodes("/Setting/FileInfos/*");
            if (nl == null)
                return ht;
            foreach (XmlNode n in nl)
            {
                string strVal = GetNodeAttrVal(n, "Value");
                string strNodeName = n.Name;
                ht.Add(strNodeName, strVal);
            }
            return ht;
        }

        public void SetLangKeyInfoForString(ref string strVal, NameObjectDictionary htSrc)
        {
            foreach (string strKey in htSrc.Keys)
            {
                if (strVal.IndexOf(strKey) > -1)
                {
                    strVal = strVal.Replace(htSrc[strKey].ToString(), strKey);
                }
            }
        }


        public void CopyCode(string sourceDirPath, string keyVal)
        {
            var langHelper = new LanguageHelper();
            string targetDirPath = sourceDirPath + "_" + keyVal;
            var scSourceFileFullNames = new StringCollection();
            langHelper.GetDirAllFileNamesForPro(sourceDirPath, scSourceFileFullNames);
            if (Directory.Exists(targetDirPath)) Directory.Delete(targetDirPath, true);
            foreach (string srcfileName in scSourceFileFullNames)
            {
                string strTargetFileName = srcfileName.Replace(sourceDirPath, sourceDirPath + keyVal);
                string[] ss = strTargetFileName.Split('\\');
                if (ss.Length > 1)
                {
                    var sbTempDirPath = new StringBuilder();
                    for (int i = 0; i < (ss.Length - 1); i++)
                    {
                        sbTempDirPath.Append(ss[i] + "\\");
                        if (!Directory.Exists(sbTempDirPath.ToString()))
                            Directory.CreateDirectory(sbTempDirPath.ToString());
                    }
                }
                if (File.Exists(strTargetFileName)) File.Delete(strTargetFileName);
                File.Copy(srcfileName, strTargetFileName);
            }
        }

        public NameValueCollection GetFileInfosFromLanguageSettingXml(string langSettingPath)
        {
            var ht = new NameValueCollection();
            var doc = new XmlDocument();
            doc.Load(langSettingPath);
            XmlNodeList nl = doc.SelectNodes("/Setting/FileInfos/*");
            if (nl == null)
                return ht;
            foreach (XmlNode n in nl)
            {
                string strVal = GetNodeAttrVal(n, "Value");
                string strNodeName = n.Name;
                ht.Add(strNodeName, strVal);
            }
            return ht;
        }

        public void SetLanguageInfoFileFroCreate(XmlDocument xmlDoc, string csFilePath, string languageFilePath,string langKey)
        {
            NameValueCollection nvcLangInfo = GetFileInfosFromLanguageSettingXml(languageFilePath);

            var scAfterEdit = new StringCollection();
            if (File.Exists(csFilePath))
            {
                var sr = new StreamReader(csFilePath, FileEncoding);
                try
                {
                    while (sr.Peek() > 0)
                    {
                        string rowText = sr.ReadLine();
                        string rowInfo = rowText.Trim();
                        string strOutputString = rowText;
                        if (rowInfo.Length > 0)
                        {
                            if (!(rowInfo.StartsWith("<%")) && rowInfo.IndexOf(LanguageKeyWord) > -1)
                            {
                                if (!csFilePath.EndsWith(".csproj"))
                                {
                                    foreach (string strKey in nvcLangInfo)
                                    {
                                        strOutputString = strOutputString.Replace(strKey, nvcLangInfo[strKey]);
                                    }
                                }
                            }
                            strOutputString = strOutputString.Replace("\\CN\\", "\\" + langKey + "\\").Replace("/CN/", "/" + langKey + "/");
                        }
                        scAfterEdit.Add(strOutputString);
                    }
                }
                finally
                {
                    sr.Close();
                }

                if (File.Exists(csFilePath)) File.Delete(csFilePath);
                var fs = new FileStream(csFilePath, FileMode.OpenOrCreate);
                var sw = new StreamWriter(fs, FileEncoding);
                try
                {
                    foreach (string str in scAfterEdit)
                        sw.WriteLine(str);
                }
                finally
                {
                    sw.Close();
                    fs.Close();
                }
            }
        }

        public void TempFix_SetLanguageInfoFileFroCreate(XmlDocument xmlDoc, string csFilePath, string languageFilePath, string langKey)
        {
            NameValueCollection nvcLangInfo = GetFileInfosFromLanguageSettingXml(languageFilePath);

            var scAfterEdit = new StringCollection();
            if (File.Exists(csFilePath))
            {
                var sr = new StreamReader(csFilePath, Encoding.Default);
                try
                {
                    while (sr.Peek() > 0)
                    {
                        string rowText = sr.ReadLine();
                        string rowInfo = rowText.Trim();
                        string strOutputString = rowText;
                        if (rowInfo.Length > 0)
                        {
                            if (csFilePath.IndexOf("ObjXmlReader") > -1)
                            {
                                var bb = "dfsd";
                                bb = "dfd";
                            }
                            if (!(rowInfo.StartsWith("<%")) && rowInfo.IndexOf(LanguageKeyWord)>-1)
                            {
                                if (!csFilePath.EndsWith(".csproj"))
                                {
                                    foreach (string strKey in nvcLangInfo)
                                    {
                                        var val = nvcLangInfo[strKey];
                                        strOutputString = strOutputString.Replace(strKey, val);
                                    }
                                }
                            }
                        }
                        scAfterEdit.Add(strOutputString);
                    }
                }
                finally
                {
                    sr.Close();
                }

                if (File.Exists(csFilePath)) File.Delete(csFilePath);
                var fs = new FileStream(csFilePath, FileMode.OpenOrCreate);
                var sw = new StreamWriter(fs, FileEncoding);
                try
                {
                    foreach (string str in scAfterEdit)
                        sw.WriteLine(str);
                }
                finally
                {
                    sw.Close();
                    fs.Close();
                }
            }
        }

        public void SetLanguageInfoFileForCreate(StringCollection xmlFilePaths, string languageFilePath,string langKey,
                                                 NameObjectDictionary ndInfo)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(languageFilePath);
            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            foreach (string str in xmlFilePaths)
                SetLanguageInfoFileFroCreate(xmlDoc, str, languageFilePath,langKey);
        }

        public void TempFix_SetLanguageInfoFileForCreate(StringCollection xmlFilePaths, string languageFilePath, string langKey,
                                                 NameObjectDictionary ndInfo)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(languageFilePath);
            XmlNode settingNode = xmlDoc.SelectSingleNode("Setting");
            foreach (string str in xmlFilePaths)
                TempFix_SetLanguageInfoFileFroCreate(xmlDoc, str, languageFilePath, langKey);
        }


        public const string CN2TW = "CN2TW", TW2CN = "TW2CN";

        public string LangConvert(string strOrg, _Application objWord, string typeName)
        {
            strOrg = strOrg.Replace("\r\n", "_-@");
            var sbResult = new StringBuilder();
            var scTemp = new StringCollection();
            bool isLast = false;
            const int subLen = 10000;
            while (!isLast)
            {
                if (strOrg.Length > subLen)
                {
                    scTemp.Add(strOrg.Substring(0, subLen));
                    strOrg = strOrg.Remove(0, subLen);
                }
                else
                {
                    scTemp.Add(strOrg);
                    isLast = true;
                }
            }
            foreach (string strTemp in scTemp)
            {
                objWord.Selection.TypeText(strTemp);
                if(typeName == CN2TW)
                    objWord.Selection.Range.TCSCConverter(WdTCSCConverterDirection.wdTCSCConverterDirectionSCTC, true, true);
                else if(typeName == TW2CN)
                    objWord.Selection.Range.TCSCConverter(WdTCSCConverterDirection.wdTCSCConverterDirectionTCSC, true, true);
                objWord.ActiveDocument.Select();
                sbResult.Append(objWord.Selection.Text);
            }


            string strVal = sbResult.ToString().Replace("\r", "").Replace("_-@", "\r\n");
            return strVal;
        }

        public string CN_To_TW(string strOrg)
        {
            _Application objWord = new Application();
            object t = Missing.Value;
            object nt = Missing.Value;
            object dt = Missing.Value;
            object v = true;
            Document objDocument = objWord.Documents.Add(ref t, ref nt, ref dt, ref v);
            try
            {
                return LangConvert(strOrg, objWord,CN2TW);
            }
            finally
            {
                object sc = 0;
                object of = Missing.Value;
                object rd = Missing.Value;
                objWord.Quit(ref sc, ref of, ref rd);
                objDocument = null;
                objWord = null;
            }
        }

        public string TW_To_CN(string strOrg)
        {
            _Application objWord = new Application();
            object t = Missing.Value;
            object nt = Missing.Value;
            object dt = Missing.Value;
            object v = true;
            Document objDocument = objWord.Documents.Add(ref t, ref nt, ref dt, ref v);
            try
            {
                return LangConvert(strOrg, objWord, TW2CN);
            }
            finally
            {
                object sc = 0;
                object of = Missing.Value;
                object rd = Missing.Value;
                objWord.Quit(ref sc, ref of, ref rd);
                objDocument = null;
                objWord = null;
            }
        }
    }
}